package cn.shujuhai.cms.service.impl;

import cn.shujuhai.cms.domain.EmailLog;
import cn.shujuhai.cms.domain.EmailRecord;
import cn.shujuhai.cms.domain.Recipient;
import cn.shujuhai.cms.domain.ToEmail;
import cn.shujuhai.cms.mapper.EmailRecordMapper;
import cn.shujuhai.cms.service.EmailLogService;
import cn.shujuhai.common.pluging.email.HtmlProcessor;
import cn.shujuhai.common.pluging.email.MailUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.*;


/**
 * @Author: ZhangDeZhong
 * @Date: 2025/1/2 17:19
 * @Description:
 **/
@Service
@RequiredArgsConstructor
public class SendEmailServiceImpl extends ServiceImpl<EmailRecordMapper, EmailRecord> {

    private final EmailLogService emailLogService;
    private final MailUtil mailUtil;
    private final HtmlProcessor htmlProcessor;

    /**
     * 发送邮件
     *
     * @param emailRecord   邮件信息
     * @param recipientList 收件人列表
     */
    @Async
    public void sendEmail(EmailRecord emailRecord, List<Recipient> recipientList) {
        // 使用并发安全的列表存储日志
        List<EmailLog> mailLogs = new CopyOnWriteArrayList<>();
        ToEmail toEmail = htmlProcessor.processHtml(new String(emailRecord.getContent(), StandardCharsets.UTF_8));
        toEmail.setSubject(emailRecord.getSubject());
        toEmail.setAttachment(emailRecord.getEmailAttachment());
        // 创建线程池（根据需要调整线程池大小）
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);

        // 用于确保所有任务完成后再保存日志
        CountDownLatch latch = new CountDownLatch(recipientList.size());

        // 定义邮件发送逻辑
        for (int i = 0; i < recipientList.size(); i++) {
            Recipient recipient = recipientList.get(i);
            // 安排延迟发送任务
            executorService.schedule(() -> {
                try {
                    toEmail.setTo(recipient.getEmail());
                    toEmail.setToName(recipient.getName());
                    // 发送邮件
                    mailUtil.htmlEmail(toEmail);
                    // 记录发送成功的日志
                    logMailDelivery(mailLogs, recipient, emailRecord, true, null);
                } catch (Exception e) {
                    // 记录发送失败的日志
                    logMailDelivery(mailLogs, recipient, emailRecord, false, e.getMessage());
                } finally {
                    // 完成一个任务，计数器减一
                    latch.countDown();
                    this.update(Wrappers.<EmailRecord>lambdaUpdate()
                            .set(EmailRecord::getCount, recipientList.size() - latch.getCount())
                            .eq(EmailRecord::getId, emailRecord.getId()));
                }
            }, i * 10L, TimeUnit.SECONDS); // 每个任务延迟 i 分钟执行
        }

        // 等待所有任务完成后再保存日志
        try {
            latch.await(1, TimeUnit.DAYS); // 等待所有任务完成
            this.emailLogService.saveBatch(mailLogs); // 保存日志
            this.update(Wrappers.<EmailRecord>lambdaUpdate()
                    .set(EmailRecord::getStatus, 3)
                    .eq(EmailRecord::getId, emailRecord.getId()));
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt(); // 恢复中断状态
            throw new RuntimeException("邮件发送任务中断", e);
        } finally {
            executorService.shutdown(); // 确保线程池关闭
        }
    }


    /**
     * 将邮件发送结果记录到邮件日志表的方法。
     *
     * @param mailLogs    邮件日志列表，用于批量记录邮件发送结果
     * @param recipient   收件人信息，可能为null如果找不到对应的收件人
     * @param emailRecord 邮件记录
     * @param success     是否发送成功
     * @param message     附加消息，如失败原因
     */
    private void logMailDelivery(List<EmailLog> mailLogs, Recipient recipient, EmailRecord emailRecord, boolean success, String message) {
        // 创建邮件日志对象
        EmailLog mailLog = new EmailLog();
        mailLog.setEmailId(emailRecord.getId()); // 设置邮件日志的邮件ID
        mailLog.setRecipientId(recipient != null ? recipient.getId() : null); // 设置邮件日志的收件人ID，如果收件人不存在则为null
        mailLog.setStatus(success ? 1 : 0); // 设置邮件日志的状态，1表示失败，0表示成功
        mailLog.setMessage(message); // 设置邮件日志的附加消息，如失败原因
        mailLog.setSendTime(LocalDateTime.now()); // 设置邮件日志的发送时间

        // 将邮件日志对象添加到列表中，以便后续批量保存
        mailLogs.add(mailLog);
    }

}
